#include "RenderComponent.h"

RenderComponent::RenderComponent() : Component("RenderComponent"),
	mGo(0),
	mEntity(0),
	mOBBox(0)
{
	init();
}

RenderComponent::RenderComponent(ComponentContainer* c, const std::string& name) : Component(c, name),
	mGo(0),
	mEntity(0),
	mOBBox(0)
{
	mMeshName = new Property<std::string>("name");
	*mMeshName = string("Cube.001.mesh");

	init();
}


RenderComponent::RenderComponent(ComponentContainer* c, const std::string& name, const std::string& mesh) : Component(c, name),
	mGo(0),
	mEntity(0),
	mOBBox(0)
{
	mMeshName = new Property<std::string>("name");
	*mMeshName = mesh;

	init();
}

RenderComponent::~RenderComponent()
{
	_deleteOBBox();
}


void RenderComponent::init()
{
	assert(mContainer!=NULL);
	mGo = dynamic_cast<GameObject*>(mContainer);
	assert(mGo!=NULL);

	mOBBox = 0;

	Object mesh;
	if(mMeshName==0 && mEntity!=0)
		{
			mMeshName = new Property<std::string>("name");
			Ogre::Mesh* m = mEntity->getMesh().get();
			*mMeshName = m->getName();
		}

	mesh.addProperty<std::string>("name", *mMeshName);
	mRenderer.addProperty<Object>("mesh", mesh);

	Property<std::string>* name = new Property<std::string>("name");
	name->onChanged.connect( sigc::mem_fun(this, &RenderComponent::updateMaterial) );
	mMaterial.addProperty(dynamic_cast<IProperty*>(name));

	Property<bool>* castShadows = new Property<bool>("castShadows");
	*castShadows = true;
	castShadows->onChanged.connect( sigc::mem_fun(this, &RenderComponent::updateMaterial) );
	mMaterial.addProperty(dynamic_cast<IProperty*>(castShadows));

	mRenderer.addProperty<Object>("material", mMaterial);

	/// TODO:
	SceneManager* sm = Ogre::Root::getSingleton().getSceneManagerIterator().getNext();
	assert(sm);

	if(!mEntity)
		mEntity = sm->createEntity(*mMeshName);

	UserObjectBindings uob = mEntity->getUserObjectBindings();
	uob.setUserAny(Any(static_cast<BaseGameObject*>(mGo)));
	mEntity->setUserAny(Any(static_cast<BaseGameObject*>(mGo)));

// lets build these anyway...
	mEntity->getMesh()->buildTangentVectors();

	SceneNode* node = mGo->getProperty<SceneNode*>("scenenode");
	assert(node!=NULL);

	// skip if already attached...
//	if(mEntity->getParentNode()!=NULL)
	if(mEntity->getParentNode()!=node)
		node->attachObject(mEntity);

	mGo->addProperty<Object>("renderer", mRenderer);
	mGo->addProperty<Entity*>("entity", mEntity);

	mShowOBBox = new Property<bool>("showOBBox", false);
	obboxCon = mShowOBBox->onChanged.connect( sigc::mem_fun(this, &RenderComponent::showOBBox) );
	mGo->addProperty(dynamic_cast<IProperty*>(mShowOBBox));

}

void RenderComponent::setMaterialName(std::string name)
{
	mEntity->setMaterialName(name);
}

void RenderComponent::updateMaterial()
{
	try
		{
			setMaterialName(mMaterial.getProperty<std::string>("name"));
			mEntity->setCastShadows(mMaterial.getProperty<bool>("castShadows"));
		}
	catch(ObjectException& e)
		{
			std::cout << e.what() << std::endl;
		}
}

void RenderComponent::_createOBBox()
{
	if(mOBBox!=0) return;

	if(!mGo->hasProperty("entity")) return;
	if(!mGo->hasProperty("scenenode")) return;

	mOBBox = new OBBoxRenderable();

	Entity* ent = mGo->getProperty<Entity*>("entity");
	SceneNode* node = mGo->getProperty<SceneNode*>("scenenode");

	mOBBox->setupVertices(ent->getBoundingBox());
//	mOBBox->setupVertices(mEntity->getBoundingBox());
	node->attachObject(mOBBox);
}

void RenderComponent::_deleteOBBox()
{
	if(mOBBox==0) return;

	try
		{
			if(mGo->hasProperty("scenenode"))
				{
					SceneNode* node = mGo->getProperty<SceneNode*>("scenenode");
					if(node!=NULL && node->numAttachedObjects()!=0)
						node->detachObject(mOBBox);
				}

			delete mOBBox;
			mOBBox = 0;
		}
	catch(Ogre::Exception& e)
		{
			cout << e.getDescription() << endl;
		}
}

void RenderComponent::showOBBox()
{
//	if(mShowOBBox==true)
	if(mGo->getProperty<bool>("showOBBox"))
		_createOBBox();
	else
		_deleteOBBox();


}
